package com.example.util.encryption;

import com.example.core.error.EncryptionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.math.BigInteger;
import java.security.Key;
import java.security.MessageDigest;

/**
 * 加密util
 * 
 * @author wangkai
 *
 * @date: 2019年5月31日 上午11:25:39
 */
public class EncryptionUtil {

	private static Logger log= LoggerFactory.getLogger(EncryptionUtil.class);
	/**
	 * 偏移变量，固定占8位字节
	 */
	private final static String IV_PARAMETER = "00000000";
	/**
	 * 密钥算法
	 */
	private static final String ALGORITHM = "DES";
	/**
	 * 加密/解密算法-工作模式-填充模式
	 */
	private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
	/**
	 * 默认编码
	 */
	private static final String CHARSET = "utf-8";


	/**
	 * MD5加密
	 *
	 * @param password
	 * @param salt
	 *            盐
	 * @return
	 */
	public static String encryptionMd5(String password, String salt) {
		StringBuffer newPassword = new StringBuffer(password);
		if (salt != null && salt.trim().length() > 0) {
			newPassword.append(salt);
		}
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(newPassword.toString().getBytes());
			return new BigInteger(1, md.digest()).toString(16);
		} catch (Exception e) {
			log.error("md5加密错误异常：{}",e.getMessage());
		}
		return null;
	}

	/**
	 * MD5加密
	 *
	 * @param password
	 * @param salt
	 *            盐
	 * @param num
	 *            加密（md5(md5(''))）
	 * @return
	 */
	public static String encryptionMd5(String password, String salt, int num) {
		StringBuffer newPassword = new StringBuffer(password);
		if (salt != null && salt.trim().length() > 0) {
			newPassword.append(salt);
		}
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			if (num == 1 || num == 0) {
				md.update(newPassword.toString().getBytes());
				return new BigInteger(1, md.digest()).toString(16);
			} else {
				String ps = newPassword.toString();
				for (int i = 0; i < num; i++) {
					if (i == 0) {
						md.update(ps.getBytes());
					} else {
						if (salt != null && salt.trim().length() > 0) {
							md.update(new String(ps + salt).getBytes());
						} else {
							md.update(new String(ps).getBytes());
						}
					}
					ps = new BigInteger(1, md.digest()).toString(16);
				}
				return ps;
			}
		} catch (Exception e) {
			log.error("md5加密错误异常：{}",e.getMessage());
		}
		return null;
	}

	/**
	 * base64加密
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static String encryptBASE64(byte[] key)   {
		try {
			return (new BASE64Encoder()).encodeBuffer(key);
		}catch (Exception e){
			log.error("base64加密异常：{}",e.getMessage());
		}
		return null;
	}

	/**
	 * base64解密
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptBASE64(String key)   {
		try {
			return (new BASE64Decoder()).decodeBuffer(key);
		}catch (Exception e){
			log.error("base64加密异常：{}",e.getMessage());
		}
		return null;
	}

	/////////////////////////////DES加密/解密///////////////////////////////////////
	/**
	 * 生成key
	 *
	 * @param password
	 * @return
	 * @throws Exception
	 */
	private static Key generateKey(String password) throws Exception {
		DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET));
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		return keyFactory.generateSecret(dks);
	}


	/**
	 * DES加密字符串
	 *
	 * @param password 加密密码，长度不能够小于8位
	 * @param data 待加密字符串
	 * @return 加密后内容
	 */
	public static String encryptDES(String password, String data) {
		if (password== null || password.length() < 8) {
			throw new EncryptionException("加密失败，key不能小于8位");
		}
		if (data == null) throw new EncryptionException("加密失败，data不能为空");
		try {
			Key secretKey = generateKey(password);
			Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
			IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
			cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
			byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));
			return encryptBASE64(bytes);
		} catch (Exception e) {
			log.error("DES加密失敗：{}",e.getMessage());
			throw new EncryptionException("DES加密失敗");
		}
	}

	/**
	 * DES解密字符串
	 *
	 * @param password 解密密码，长度不能够小于8位
	 * @param data 待解密字符串
	 * @return 解密后内容
	 */
	public static String decryptDES(String password, String data) {
		if (password== null || password.length() < 8) {
			throw new EncryptionException("解密失败，key不能小于8位");
		}
		if (data == null) throw new EncryptionException("解密失败，data不能为空");
		try {
			Key secretKey = generateKey(password);
			Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
			IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
			cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
			return new String(cipher.doFinal(decryptBASE64(data)), CHARSET);
		} catch (Exception e) {
			log.error("DES解密失敗异常：{}",e.getMessage());
			throw new EncryptionException("DES解密失敗");
		}
	}

}
